package com.bestcem.xm.award.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.bp.pay.grpc.v1.common.FinanceArgs;
import com.bestcem.bp.pay.grpc.v1.enums.ActivityTypeEnum;
import com.bestcem.bp.pay.grpc.v1.services.*;
import com.bestcem.xm.award.config.WxConfig;
import com.bestcem.xm.award.constant.Constants;
import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.constant.RequestAwardConstants;
import com.bestcem.xm.award.controller.convert.AwardConvert;
import com.bestcem.xm.award.entity.mongo.BaseEntity;
import com.bestcem.xm.award.entity.pojo.AwardAwardDO;
import com.bestcem.xm.award.entity.pojo.AwardRequestDO;
import com.bestcem.xm.award.enums.AwardRequestStatusEnum;
import com.bestcem.xm.award.enums.AwardSettlementEnum;
import com.bestcem.xm.award.enums.AwardStatusEnum;
import com.bestcem.xm.award.enums.AwardTypeEnum;
import com.bestcem.xm.award.grpc.client.ActivityGrpcService;
import com.bestcem.xm.award.grpc.client.ProjectGrpcService;
import com.bestcem.xm.award.grpc.client.WalletGrpcService;
import com.bestcem.xm.award.mq.dto.RedPacketAwardStartDTO;
import com.bestcem.xm.award.mq.dto.RedPacketAwardStopDTO;
import com.bestcem.xm.award.service.AwardMqHandler;
import com.bestcem.xm.award.service.DrawCommonService;
import com.bestcem.xm.award.service.bo.award.AwardAwardBO;
import com.bestcem.xm.award.service.dto.ChangeActivityStatusBodyDTO;
import com.bestcem.xm.award.service.dto.awardaward.CreateAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.DeleteAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.UpdateAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.UpdateAwardStatusDTO;
import com.bestcem.xm.award.service.dto.requestaward.RedPacketAwardDTO;
import com.bestcem.xm.award.service.dto.requestaward.RequestAwardDTO;
import com.bestcem.xm.award.service.mq.send.AwardMessageService;
import com.bestcem.xm.award.util.MoneyUtil;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.JsonUtil;
import com.bestcem.xm.common.core.uitls.SignUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.bestcem.xm.award.enums.AwardRequestStatusEnum.PASS;
import static com.bestcem.xm.award.enums.AwardStatusEnum.*;
import static com.bestcem.xm.award.enums.AwardTypeEnum.REDPACKET;

/**
 * @author sh.pei <sh.pei@idiaoyan.com>
 * @version v1.0
 * @date 2021/7/8 13:49
 */
@Slf4j
@Service
public class RedPacketAwardServiceImpl extends AbstractAwardAwardService {

    @Value("${url.wjlink_long_to_short_url}")
    private String longToShortUrl;

    @Resource
    private RestTemplate restTemplate;

    @Autowired
    private WalletGrpcService walletGrpcService;

    @Autowired
    private ActivityGrpcService activityGrpcService;

    @Autowired
    private WxConfig wxConfig;

    //@Autowired
    //private ShortLinkGrpcService shortLinkGrpcService;

    @Autowired
    private AwardMqHandler awardMqHandler;

    @Autowired
    private ProjectGrpcService projectGrpcService;

    @Resource
    private DrawCommonService drawCommonService;
//    @Autowired
//    private RabbitMqConstantConfig rabbitMqConstantConfig;

    /*@Autowired
    private PackUtil packUtil;*/

    @Autowired
    private AwardMessageService awardMessageService;

    @Autowired
    private RedisService redisService;

    /**
     * 红包奖励新增或修改时检验
     *
     * @param awardAward 奖励数据
     * @return
     */
    @Override
    public ServiceResult<String> independentCheckAward(AwardAwardBO awardAward) {
        Optional<AwardAwardBO> optional = Optional.of(awardAward);
        // 未设置时间或时间在当前时间之前,设置开始时间为当前时间
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStartTime).isPresent() || awardAward.getBasic().getStartTime().getTime() < System.currentTimeMillis()) {
            awardAward.getBasic().setStartTime(DateUtil.now());
        }
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStopTime).isPresent()) {
            return ServiceResult.fail("奖励结束时间缺失！");
        }
        if (awardAward.getBasic().getStopTime().compareTo(awardAward.getBasic().getStartTime()) < 0) {
            return ServiceResult.fail("结束时间不能在开始时间或当前时间之前！");
        }
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getName).isPresent()) {
            return ServiceResult.fail("红包详情不能为空！");
        }
        if (awardAward.getBasic().getName().length() > Constants.TEN) {
            return ServiceResult.fail(String.format("红包详情长度在%d以内！", Constants.TEN));
        }
        if (awardAward.getBasic().getDisplayName() != null && awardAward.getBasic().getDisplayName().length() > Constants.TEN) {
            return ServiceResult.fail(String.format("企业名称长度在%d以内！", Constants.TEN));
        }
        Optional<BigDecimal> singleAmount = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getSinAmount);
        Optional<BigDecimal> totalAmount = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalAmount);
        Optional<Integer> totalCount = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalCount);
        if (!totalCount.isPresent() || totalCount.get() == 0) {
            return ServiceResult.fail("红包个数缺失！");
        }
        // 拼手气红包
        if (totalAmount.isPresent() && totalAmount.get().compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal sinAmount = totalAmount.get().divide(new BigDecimal(totalCount.get()), 8, RoundingMode.DOWN);
            if (sinAmount.compareTo(new BigDecimal(Constants.MIN_REDPACKET)) < 0) {
                return ServiceResult.fail(String.format("红包平均金额必须大于等于%s元！", Constants.MIN_REDPACKET));
            }
            if (sinAmount.compareTo(new BigDecimal(Constants.MAX_REDPACKET)) > 0) {
                return ServiceResult.fail(String.format("单个红包金额不能大于%s元！", Constants.MAX_REDPACKET));
            }
            awardAward.getBasic().setSinAmount(null);
        } // 普通红包
        else {
            if (!singleAmount.isPresent() || singleAmount.get().compareTo(new BigDecimal(Constants.MIN_REDPACKET)) < 0) {
                return ServiceResult.fail(String.format("红包平均金额必须大于等于%s元！", Constants.MIN_REDPACKET));
            } else if (singleAmount.get().compareTo(new BigDecimal(Constants.MAX_REDPACKET)) > 0) {
                return ServiceResult.fail(String.format("单个红包金额不能大于%s元！", Constants.MAX_REDPACKET));
            }
            awardAward.getBasic().setTotalAmount(null);
        }
        // 最大参与人数
        Optional<Long> prob = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getProbability);
        if (prob.isPresent() && prob.get() > Constants.FIVE_HUNDRED_THOUSAND) {
            return ServiceResult.fail(String.format("预计参与人数不能大于%s！", Constants.FIVE_HUNDRED_THOUSAND_STR));
        }
        // 去除无用配置
        awardAward.setIssue(null);
        awardAward.setAwards(null);
        awardAward.setPage(null);
        return ServiceResult.success();
    }

    /**
     * 检查钱包余额
     *
     * @param walletId
     * @param balance
     * @return
     */
    private ServiceResult<String> checkWalletBalance(String walletId, BigDecimal balance) {
        GetWalletResponse walletResp = walletGrpcService.getWallet(GetWalletRequest.newBuilder().setId(walletId).build());
        if (Code.OK_VALUE != walletResp.getStatus().getCodeValue()) {
            return ServiceResult.fail(walletResp.getStatus().getMessage());
        }
        if (MoneyUtil.centToYuan(Optional.of(walletResp.getWallet()).map(WalletInfo::getBalance).orElse(0)).compareTo(balance) < 0) {
            return ServiceResult.fail("钱包余额不足！");
        }
        return ServiceResult.success();
    }

    /**
     * 创建微信红包奖励
     *
     * @param createAwardDTO 创建奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> createAward(CreateAwardDTO createAwardDTO) {
        ServiceResult hasPermission = hasRedPacketAwardPermission(createAwardDTO.getAwardAward().getOrgId());
        if (!hasPermission.isSuccess()) {
            return hasPermission;
        }
        Optional<AwardAwardBO> optional = Optional.of(createAwardDTO.getAwardAward());
        BigDecimal totalAmt = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalAmount).orElse(null);
        if (Objects.isNull(totalAmt)) {
            totalAmt = optional.get().getBasic().getSinAmount().multiply(new BigDecimal(optional.get().getBasic().getTotalCount()));
        }

        // 项目名称
        ServiceResult<String> projectTitleResult = projectGrpcService.getProjectTitle(createAwardDTO.getAwardAward().getProjectId());
        if (!projectTitleResult.isSuccess()) {
            return ServiceResult.fail(projectTitleResult.getMsg());
        }
        createAwardDTO.setProjectTitle(projectTitleResult.getData());

        log.info("start 创建钱包活动");
        // 创建钱包活动
        CreateActivityRequest createActivityRequest = CreateActivityRequest.newBuilder().setWalletId(createAwardDTO.getWalletId())
                .setActivity(ActivityArgs.newBuilder().setName(optional.map(AwardAwardBO::getName).get()).setAmount(MoneyUtil.yuanToCent(totalAmt).intValue()).setNum(optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalCount).get()).setSendRemark("").setTypeValue(optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalAmount).isPresent() ? ActivityTypeEnum.ActivityType.RANDOM_VALUE : ActivityTypeEnum.ActivityType.NORM_VALUE).build()).build();
        CreateActivityResponse createActivityResponse = activityGrpcService.createActivity(createActivityRequest);
        log.info("end 创建钱包活动:" + createActivityResponse.getStatus() + "," + createActivityResponse.getStatus().getMessage());

        if (Code.OK_VALUE != createActivityResponse.getStatus().getCodeValue()) {
            return ServiceResult.fail(createActivityResponse.getStatus().getMessage());
        }
        // 设置活动id
        createAwardDTO.getAwardAward().setActivityId(createActivityResponse.getId());
        //校验钱包余额
        ServiceResult<String> result = checkWalletBalance(createAwardDTO.getWalletId(), totalAmt);
        log.info("start result校验钱包余额 " + JSON.toJSONString(result));
        if (!result.isSuccess()) {
            return result;
        }
        // 单个微信号领取限制: 最多一次
        createAwardDTO.getAwardAward().getRule().setWin(Constants.ONE);
        // 创建奖励
        AwardAwardDO awardDO = AwardConvert.awardAwardBOToAwardAwardDO(createAwardDTO.getAwardAward());
        if (log.isInfoEnabled()) {
            log.info("[award] 奖励转换: AwardAwardBO:{} AwardAwardDO:{}", JSON.toJSONString(createAwardDTO.getAwardAward()), JSON.toJSONString(awardDO));
        }
        AwardAwardDO awardAwardDO = awardAwardDao.save(awardDO);
        // 预扣钱包款项
        ActivateActivityRequest activityRequest = ActivateActivityRequest.newBuilder().setId(awardAwardDO.getActivityId()).setFinanceArgs(FinanceArgs.newBuilder()
                .setOpUserId(createAwardDTO.getUserId()).setOpUserName(createAwardDTO.getUserName()).setRemark(generateRemark(createAwardDTO.getProjectTitle(), awardAwardDO.getName())).build()).build();
        ActivateActivityResponse activityResponse = activityGrpcService.activateActivity(activityRequest);
        // 预扣钱包款项失败,结束红包活动
        if (Code.OK_VALUE != activityResponse.getStatus().getCodeValue()) {
            AwardAwardDO update = new AwardAwardDO();
            update.setStatus(AwardStatusEnum.FINISH.getIndex());
            awardAwardDao.updateByAwardId(awardAwardDO.getId(), update);
            return ServiceResult.fail(activityResponse.getStatus().getMessage());
        }
        sendMqMsg(awardAwardDO, createAwardDTO.getProjectTitle());
        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 发送延迟消息
     *
     * @param awardAwardDO 奖励
     * @param projectTile  项目title
     */
    private void sendMqMsg(AwardAwardDO awardAwardDO, String projectTile) {
        sendMqStartMsg(awardAwardDO);
        sendMqStopMsg(awardAwardDO, projectTile);

    }

    public void sendMqStartMsg(AwardAwardDO awardAwardDO) {
        RedPacketAwardStartDTO redPacketAwardStartDTO = new RedPacketAwardStartDTO();
        redPacketAwardStartDTO.setAwardId(awardAwardDO.getId());
        redPacketAwardStartDTO.setStartTime(awardAwardDO.getBasic().getStartTime());
//        try {
//            mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.RED_PACKET_START_TOPIC, redPacketAwardStartDTO, awardAwardDO.getBasic().getStartTime());
//        } catch (JsonProcessingException e) {
//            log.error("发送延迟开始红包奖励消息失败:" + awardAwardDO.getId(), e);
//        }
        awardMessageService.awardRedPacketStartSend(redPacketAwardStartDTO, awardAwardDO.getBasic().getStartTime());
    }

    public void sendMqStopMsg(AwardAwardDO awardAwardDO, String projectTile) {
        RedPacketAwardStopDTO redPacketAwardStopDTO = new RedPacketAwardStopDTO();
        redPacketAwardStopDTO.setAwardId(awardAwardDO.getId());
        redPacketAwardStopDTO.setStopTime(awardAwardDO.getBasic().getStopTime());
        ChangeActivityStatusBodyDTO changeActivityStatusBodyDTO = new ChangeActivityStatusBodyDTO();
        changeActivityStatusBodyDTO.setRemark(generateRemark(projectTile, awardAwardDO.getName()));
        changeActivityStatusBodyDTO.setOpUserId(Constants.SYS_OP_USER_ID);
        changeActivityStatusBodyDTO.setOpUserName(Constants.SYS_OP_USER_NAME);
        redPacketAwardStopDTO.setBodyDTO(changeActivityStatusBodyDTO);
//        try {
//            mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.RED_PACKET_STOP_TOPIC, redPacketAwardStopDTO, awardAwardDO.getBasic().getStopTime());
//        } catch (JsonProcessingException e) {
//            log.error("发送延迟结束红包奖励消息失败:" + awardAwardDO.getId(), e);
//        }
        awardMessageService.awardRedPacketStopSend(redPacketAwardStopDTO, awardAwardDO.getBasic().getStopTime());
    }

    /**
     * 生成remark
     *
     * @param projectTitle
     * @param name
     * @return
     */
    private String generateRemark(String projectTitle, String name) {
        StringBuilder sb = new StringBuilder();
        sb.append(projectTitle).append("-微信红包");
        if (StrUtil.isNotEmpty(name)) {
            sb.append("-").append(name);
        }
        if (sb.length() > Constants.TWO_HUNDRED_AND_FIFTY_FIVE) {
            return sb.substring(0, Constants.TWO_HUNDRED_AND_FIFTY_FIVE);
        } else {
            return sb.toString();
        }
    }

    /**
     * 修改奖励
     *
     * @param updateAwardDTO 更新奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> updateAward(UpdateAwardDTO updateAwardDTO) {
        Optional<AwardAwardBO> optional = Optional.of(updateAwardDTO.getAwardAward());
        BigDecimal totalAmt = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalAmount).orElse(null);
        if (Objects.isNull(totalAmt)) {
            totalAmt = optional.get().getBasic().getSinAmount().multiply(new BigDecimal(optional.get().getBasic().getTotalCount()));
        }

        // 项目名称
        ServiceResult<String> projectTitleResult = projectGrpcService.getProjectTitle(updateAwardDTO.getAwardAward().getProjectId());
        if (!projectTitleResult.isSuccess()) {
            return ServiceResult.fail(projectTitleResult.getMsg());
        }
        updateAwardDTO.setProjectTitle(projectTitleResult.getData());

        // 结束之前的钱包活动
        FinishActivityRequest finishActivityRequest = FinishActivityRequest.newBuilder().setId(updateAwardDTO.getAwardAward().getActivityId()).setFinanceArgs(FinanceArgs.newBuilder()
                .setOpUserId(updateAwardDTO.getUserId()).setOpUserName(updateAwardDTO.getUserName()).setRemark(generateRemark(updateAwardDTO.getProjectTitle(), updateAwardDTO.getAwardAward().getName())).build()).build();
        FinishActivityResponse finishActivityResponse = activityGrpcService.finishActivity(finishActivityRequest);
        if (Code.OK_VALUE != finishActivityResponse.getStatus().getCodeValue()) {
            AwardAwardDO update = new AwardAwardDO();
            update.setSettlement(AwardSettlementEnum.FAILED.getIndex());
            awardAwardDao.updateByAwardId(optional.map(BaseEntity::getId).get(), update);
            return ServiceResult.fail(finishActivityResponse.getStatus().getMessage());
        } else {
            AwardAwardDO update = new AwardAwardDO();
            update.setSettlement(AwardSettlementEnum.SUCCESS.getIndex());
            awardAwardDao.updateByAwardId(optional.map(BaseEntity::getId).get(), update);
        }

        //校验钱包余额
        ServiceResult<String> result = checkWalletBalance(updateAwardDTO.getWalletId(), totalAmt);
        if (!result.isSuccess()) {
            updateAwardDTO.getAwardAward().setStatus(AwardStatusEnum.FINISH.getIndex());
            awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(updateAwardDTO.getAwardAward()));
            return result;
        }

        // 创建钱包活动
        CreateActivityRequest createActivityRequest = CreateActivityRequest.newBuilder().setWalletId(updateAwardDTO.getWalletId())
                .setActivity(ActivityArgs.newBuilder().setName(optional.map(AwardAwardBO::getName).get()).setAmount(MoneyUtil.yuanToCent(totalAmt).intValue()).setNum(optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalCount).get()).setSendRemark("").setTypeValue(optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalAmount).isPresent() ? ActivityTypeEnum.ActivityType.RANDOM_VALUE : ActivityTypeEnum.ActivityType.NORM_VALUE).build()).build();
        CreateActivityResponse createActivityResponse = activityGrpcService.createActivity(createActivityRequest);
        if (Code.OK_VALUE != createActivityResponse.getStatus().getCodeValue()) {
            updateAwardDTO.getAwardAward().setStatus(AwardStatusEnum.FINISH.getIndex());
            awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(updateAwardDTO.getAwardAward()));
            return ServiceResult.fail(createActivityResponse.getStatus().getMessage());
        }
        // 设置活动id
        updateAwardDTO.getAwardAward().setActivityId(createActivityResponse.getId());
        // 更新奖励奖励
        updateAwardDTO.getAwardAward().setStatus(AwardStatusEnum.INACTIVE.getIndex());
        // 单个微信号领取限制: 最多一次
        updateAwardDTO.getAwardAward().getRule().setWin(Constants.ONE);
        AwardAwardDO awardAwardDO = awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(updateAwardDTO.getAwardAward()));
        // 预扣钱包款项
        ActivateActivityRequest activityRequest = ActivateActivityRequest.newBuilder().setId(awardAwardDO.getActivityId()).setFinanceArgs(FinanceArgs.newBuilder()
                .setOpUserId(updateAwardDTO.getUserId()).setOpUserName(updateAwardDTO.getUserName()).setRemark(generateRemark(updateAwardDTO.getProjectTitle(), awardAwardDO.getName())).build()).build();
        ActivateActivityResponse activityResponse = activityGrpcService.activateActivity(activityRequest);
        if (Code.OK_VALUE != activityResponse.getStatus().getCodeValue()) {
            AwardAwardDO update = new AwardAwardDO();
            update.setStatus(AwardStatusEnum.FINISH.getIndex());
            awardAwardDao.updateByAwardId(awardAwardDO.getId(), update);
            return ServiceResult.fail(activityResponse.getStatus().getMessage());
        }
        sendMqMsg(awardAwardDO, updateAwardDTO.getProjectTitle());

        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 修改奖励状态
     *
     * @param updateAwardStatusDTO 更新奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> updateAwardStatus(UpdateAwardStatusDTO updateAwardStatusDTO) {

        Integer newStatus = updateAwardStatusDTO.getStatus();
        Integer oldStatus = updateAwardStatusDTO.getOldStatus();
        if (newStatus.intValue() == oldStatus.intValue()) {
            return ServiceResult.success();
        }
        if (!checkUpdateStatus(newStatus, oldStatus)) {
            return ServiceResult.fail("当前状态无法转移至新状态！");
        }
        // 再次检查
        AwardAwardDO awardAwardDO = awardAwardDao.findById(updateAwardStatusDTO.getAwardId());
        if (awardAwardDO == null) {
            return ServiceResult.fail("奖励不存在！");
        }

        // 项目名称
        ServiceResult<String> projectTitleResult = projectGrpcService.getProjectTitle(awardAwardDO.getProjectId());
        if (!projectTitleResult.isSuccess()) {
            return ServiceResult.fail(projectTitleResult.getMsg());
        }
        updateAwardStatusDTO.setProjectTitle(projectTitleResult.getData());

        // 调用钱包修改奖励活动状态
        ChangeActivityStatusBodyDTO bodyDTO = new ChangeActivityStatusBodyDTO();
        String remark = activityGrpcService.genRemark(updateAwardStatusDTO.getProjectTitle(), AwardTypeEnum.REDPACKET.getName(), awardAwardDO.getName());
        bodyDTO.setOpUserId(Constants.SYS_OP_USER_ID);
        bodyDTO.setOpUserName(Constants.SYS_OP_USER_NAME);
        bodyDTO.setRemark(remark);
        if ((newStatus.intValue() == ACTIVE.getIndex() && oldStatus.intValue() == INACTIVE.getIndex())) {
            // 初始化奖池
            RedPacketAwardStartDTO redPacketAwardStartDTO = new RedPacketAwardStartDTO();
            redPacketAwardStartDTO.setAwardId(awardAwardDO.getId());
            redPacketAwardStartDTO.setStartTime(awardAwardDO.getBasic().getStartTime());
            boolean startRedPacketAwardResult = awardMqHandler.startRedPacketAward(redPacketAwardStartDTO);
            if (!startRedPacketAwardResult) {
                return ServiceResult.fail("初始化奖池失败！");
            }
            // 更新状态
            AwardAwardDO update = new AwardAwardDO();
            update.setStatus(newStatus);
            if (update.getBasic() == null) {
                update.setBasic(new AwardAwardDO.Basic());
            }
            update.getBasic().setStartTime(DateUtil.getDate());
            awardAwardDao.updateByAwardId(updateAwardStatusDTO.getAwardId(), update);
            return ServiceResult.success(awardAwardDO.getId());
        } else {
            boolean result = activityGrpcService.changeActivityStatus(awardAwardDO.getActivityId(), newStatus, oldStatus, bodyDTO);
            if (result) {
                AwardAwardDO update = new AwardAwardDO();
                update.setStatus(newStatus);
                update.setSettlement(AwardSettlementEnum.SUCCESS.getIndex());
                awardAwardDao.updateByIdAndStatus(updateAwardStatusDTO.getAwardId(), updateAwardStatusDTO.getOldStatus(), update);
                return ServiceResult.success(awardAwardDO.getId());
            } else {
                if (FINISH.getIndex() == newStatus) {
                    AwardAwardDO update = new AwardAwardDO();
                    update.setSettlement(AwardSettlementEnum.FAILED.getIndex());
                    awardAwardDao.updateByAwardId(awardAwardDO.getId(), update);
                }
                return ServiceResult.fail("当前状态无法转移至新状态！");
            }
        }
    }

    @Override
    public ServiceResult<String> beforeFinishAward(String awardId) {
        AwardAwardDO awardAwardDO = awardAwardDao.findById(awardId);
        // 查询项目名称
        ServiceResult<String> projectTitleResult = projectGrpcService.getProjectTitle(awardAwardDO.getProjectId());
        if (!projectTitleResult.isSuccess()) {
            return ServiceResult.fail(projectTitleResult.getMsg());
        }
        // 调用钱包结束活动
        ChangeActivityStatusBodyDTO bodyDTO = new ChangeActivityStatusBodyDTO();
        String remark = activityGrpcService.genRemark(projectTitleResult.getData(), AwardTypeEnum.REDPACKET.getName(), awardAwardDO.getName());
        bodyDTO.setOpUserId(Constants.SYS_OP_USER_ID);
        bodyDTO.setOpUserName(Constants.SYS_OP_USER_NAME);
        bodyDTO.setRemark(remark);
        boolean changeActivityStatus = activityGrpcService.changeActivityStatus(awardAwardDO.getActivityId(), AwardStatusEnum.FINISH.getIndex(),
                awardAwardDO.getStatus(), bodyDTO);
        if (!changeActivityStatus) {
            return ServiceResult.fail("红包活动结束失败");
        }
        // 概率红包，使用redis存储奖池后需要清理奖池
        redisService.del(String.format(RedisKeyConstant.AWARD_POOL, awardId));
        return ServiceResult.success();
    }

    /**
     * 删除奖励
     *
     * @param param 删除奖励入参
     * @return
     */
    @Override
    public ServiceResult<Integer> deleteAward(DeleteAwardDTO param) {

        // 再次检查
        AwardAwardDO awardAwardDO = awardAwardDao.findById(param.getAwardId());
        if (awardAwardDO == null) {
            return ServiceResult.fail("奖励不存在！");
        }

        // 项目名称
        ServiceResult<String> projectTitleResult = projectGrpcService.getProjectTitle(awardAwardDO.getProjectId());
        if (!projectTitleResult.isSuccess()) {
            return ServiceResult.fail(projectTitleResult.getMsg());
        }

        // 结束活动
        UpdateAwardStatusDTO updateAwardStatusDTO = new UpdateAwardStatusDTO();
        updateAwardStatusDTO.setOrgId(param.getOrgId());
        updateAwardStatusDTO.setAwardId(param.getAwardId());
        updateAwardStatusDTO.setStatus(FINISH.getIndex());
        updateAwardStatusDTO.setProjectTitle(projectTitleResult.getData());
        updateAwardStatusDTO.setOldStatus(awardAwardDO.getStatus());
        updateAwardStatusDTO.setUserId(Constants.SYS_OP_USER_ID);
        updateAwardStatusDTO.setUserName(Constants.SYS_OP_USER_NAME);
        ServiceResult<String> result = updateAwardStatus(updateAwardStatusDTO);
        if (!result.isSuccess()) {
            return ServiceResult.fail(result.getMsg());
        }

        // 删除钱包活动
        DeleteActivityResponse response = activityGrpcService.deleteActivity(DeleteActivityRequest.newBuilder().setId(param.getActivityId()).build());
        if (response.getStatus().getCodeValue() != Code.OK_VALUE) {
            return ServiceResult.fail(response.getStatus().getMessage());
        }
        // 删除奖励
        return super.deleteAward(param);
    }

    /**
     * 处理的奖励类型
     *
     * @return
     */
    @Override
    public AwardTypeEnum getAwardTypeEnum() {
        return REDPACKET;
    }

    @Override
    public ServiceResult<String> doRequestAward(RequestAwardDTO requestAwardDTO) {
        // 返回结构体
        RedPacketAwardDTO redPacketAwardDTO = new RedPacketAwardDTO();
        redPacketAwardDTO.setTType(REDPACKET.getIndex());
        // 奖励id
        String awardId = Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardAwardDO)
                .map(BaseEntity::getId).orElse(Constants.BLANK);
        if (StringUtils.isBlank(awardId)) {
            return ServiceResult.fail(RequestAwardConstants.MISSING_AWARD_ID);
        }
        drawCommonService.asyncRestoreAwardPool(awardId);

        // 奖励信息
        AwardAwardDO awardAwardDO = requestAwardDTO.getAwardAwardDO();
        requestAwardDTO.setAwardAwardDO(awardAwardDO);
        // 校验
        AwardRequestStatusEnum checkCostTime = awardCheck.getCheckCostTimeResult(requestAwardDTO);
        if (checkCostTime.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkCostTime);
        }
        AwardRequestStatusEnum checkInProceeding = awardCheck.checkInProceeding(requestAwardDTO);
        if (checkInProceeding.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkInProceeding);
        }
        AwardRequestStatusEnum checkProb = awardCheck.getCheckProbResult(requestAwardDTO);
        if (checkProb.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkProb);
        }
        AwardRequestStatusEnum checkDayLimit = awardCheck.getCheckDayLimitResult(requestAwardDTO);
        if (checkDayLimit.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkDayLimit);
        }
        // 待插入AWARD_REQUEST数据
        AwardRequestDO request = Optional.of(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO).orElse(null);
        if (Validator.isNull(request)) {
            return ServiceResult.fail(RequestAwardConstants.MISSING_AWARD_REQUEST);
        }
        request.setStatus(PASS.getIndex());
        // 插入AWARD_REQUEST数据
        AwardRequestDO awardRequestDO = awardRequestDao.insert(request);
        String requestId = Optional.ofNullable(awardRequestDO).map(AwardRequestDO::getId).orElse(Constants.BLANK);
        if (StringUtils.isBlank(requestId)) {
            return ServiceResult.fail(RequestAwardConstants.AWARD_REQUEST_SAVE_ERROR);
        }
        redPacketAwardDTO.setRequestId(requestId);
        RedPacketAwardDTO.Award award = new RedPacketAwardDTO.Award();
        award.setAwardId(awardId);
        award.setDeliverId(Optional.of(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getDeliverDTO).map(AwardRequestDO.Deliver::getDeliverId).orElse(null));
        award.setSurveyId(Optional.of(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getSurvey).map(AwardRequestDO.Survey::getSurveyId).orElse(null));
        award.setSurveySeq(Optional.of(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getSurvey).map(AwardRequestDO.Survey::getSeq).orElse(null));
        // 生成签名
        String drawAwardKey = signConfig.getAwardKey();
        Map<String, Object> map = JsonUtil.convertValueSnake(award, new TypeReference<Map<String, Object>>() {
        });
        String sig = SignUtil.genSign(map, drawAwardKey);
        award.setSig(sig);
        redPacketAwardDTO.setAward(award);
        // 获取微信用户code接口url
        String url = this.genPickUrl(awardId, requestId, award.getSurveyId(), award.getDeliverId());
        if (StringUtils.isBlank(url)) {
            return ServiceResult.fail(Constants.SOURCE_NOT_FOUND);
        }
        redPacketAwardDTO.setUrl(url);
        String data = JsonUtil.transferToJsonSnake(redPacketAwardDTO);
        return ServiceResult.success(data);
    }

    /**
     * 生成获取code的微信回调url
     *
     * @param awardId   奖励id
     * @param requestId 请求id
     * @param surveyId  答卷id
     * @param deliverId 投放id
     * @return 微信回调url
     */
    private String genPickUrl(String awardId, String requestId, String surveyId, String deliverId) {
        String appId = wxConfig.getAppId();
        // 十位随机字符串
        String secretKey = RandomStringUtils.random(Constants.TEN, true, true);
        // redisKey
        String key = wxConfig.getKey() + requestId;
        // redisValue
        List<String> values = new ArrayList<>();
        values.add(secretKey);
        values.add(requestId);
        String value = JsonUtil.transferToJson(values);
        // 若key不存在,则存入redis
        if (redisService.setIfAbsent(key, value)) {
            // 添加过期时间
            redisService.expire(key, wxConfig.getRedisKeyExpire(), TimeUnit.SECONDS);
        } else {
            // 若key存在,则取出value
            String redisValue = redisService.getString(key);
            if (StringUtils.isBlank(redisValue)) {
                return Constants.BLANK;
            }
            // 从value中获取secretKey
            List<String> stringList = JsonUtil.jsonToTransfer(redisValue, new TypeReference<List<String>>() {
            });
            secretKey = stringList.get(0);
        }
        String redirectUrl = String.format("%s/api/award/bonus/saas/wx_redirect/%s?", wxConfig.getSaasServerUrl(), surveyId);
        // 当前时间戳 秒
        String currentTimeMillis = Convert.toStr(Instant.now().getEpochSecond());
        // param依赖apps.survey.handlers.SurveyHandler.post接口的参数，两边需保持一致
        StringBuilder param = new StringBuilder();
        param.append("award_id=").append(awardId)
                .append("&").append("request_id=").append(requestId)
                .append("&").append("deliver_id=").append(deliverId)
                .append("&").append("ts=").append(currentTimeMillis)
                .append("&").append("v=").append(DigestUtil.md5Hex(String.join(Constants.SEPARATE, Arrays.asList(requestId, currentTimeMillis, secretKey))))
                .append("&").append("custom_domain=").append(wxConfig.getSurveySystemUrl());
        if (log.isInfoEnabled()) {
            log.info("before requestUrl:{}", redirectUrl + param.toString());
        }
        String requestUrl = null;
        try {
            requestUrl = URLEncoder.encode(redirectUrl + param.toString(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("[Award] URLEncoder.encode error", e);
        }
        if (log.isInfoEnabled()) {
            log.info("after requestUrl:{}", requestUrl);
        }
        String url = String.format(wxConfig.getOauth2AuthorizeUrl(), appId, requestUrl, wxConfig.getScope());
        if (log.isInfoEnabled()) {
            log.info("after format:{}", requestUrl);
        }
        if (wxConfig.isTest()) {
            // 测试环境写死code，免去配置公众号后台
            url = redirectUrl + param.toString() + "&code=5ec7439315377614c48f43d0";
        }
        if (log.isInfoEnabled()) {
            log.info("[Award] genPickUrl awardId {}, url {}", awardId, url);
        }
        //直接http操作
        return aioConvertShortUrl(url, null);
        /*ServiceResult<String> shortActivateUrl = aioConvertShortUrl(url, null);
        if (!shortActivateUrl.isSuccess()) {
            log.error("生成重置密码短链接失败！");
            return "";
        } else {
            return shortActivateUrl.getData();
        }*/
        // grpc 长链接转短链接
        //GetShortLinkRequest.Builder builder = GetShortLinkRequest.newBuilder();
        //builder.setLink(url);
        //GetShortLinkResponse shortLink = shortLinkGrpcService.getShortLink(builder.build());
        //if (log.isInfoEnabled()) {
        //    log.info("[Award] shortLink awardId {}, url {}, {}, {}, {}", awardId, url, shortLink.getStatus().getCode(), shortLink.getStatus().getMessage(), shortLink.getShortLink());
        //}
        //return shortLink.getStatus().getCodeValue() == Code.OK_VALUE ? shortLink.getShortLink() : Constants.BLANK;
    }

    public String aioConvertShortUrl(String url, String customDomainUrl) {
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("url", url);
        JSONObject response = wjlinkShortUrl(paramMap);
        if (response == null || response.getInteger("code") != 0) {
            throw new BusinessException("短链接服务获取出错");
        }
        log.info("Now the shorten response = {}", response.toJSONString());
        if (StringUtils.isEmpty(customDomainUrl)) {
            return response.getString("short_url");
        }
        return customDomainUrl + "/t/" + response.getString("tcode");
    }

    private JSONObject wjlinkShortUrl(Map<String, String> paramMap) {
        //RetrofitClient 构建x-www-form-urlencoded，一直有问题，换个原生写法
        try (HttpResponse response = HttpRequest.post(longToShortUrl)
                //.header(Header.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .body(JSON.toJSONString(paramMap))
                .execute()) {

            if (response.isOk()) {
                return JSONObject.parseObject(response.body());
            } else {
                return null;
            }
        }
    }

/*    public ServiceResult<String> aioConvertShortUrl(String url, String customDomainUrl) {
        // 请求第三方接口生成短链接
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("url", url);
        HttpEntity<MultiValueMap<String, Object>> param = new HttpEntity<>(map, httpHeaders);

        ResponseEntity<String> apiResponse = null;
        try {
            log.info("[award]短链接服务请求，请求路径url={},param={}", longToShortUrl, param);
            apiResponse = restTemplate.postForEntity(longToShortUrl, param, String.class);
        } catch (Exception e) {
            log.error("请求短链接服务失败", e);
        }
        if (Objects.isNull(apiResponse)) {
            return ServiceResult.fail(url, "no result", "0");
        }

        // 解析返回内容
        JSONObject response = JSON.parseObject(apiResponse.getBody());
        log.info("[award]短链接服务返回：{}", response);
        if (!response.get("code").equals(0)) {
            return ServiceResult.fail(url, response.get("msg").toString(), response.get("code").toString());
        }

        return ServiceResult.success(StringUtils.isBlank(customDomainUrl) ? response.get("short_url").toString()
                : customDomainUrl + "/t/" + response.get("tcode"));
    }*/

    public ServiceResult<String> hasRedPacketAwardPermission(String orgId) {
        /*PackageDTO pack = packUtil.getPackageByOrgId(orgId);
        if (AwardPackUtil.hasRedPacketAwardPermission(pack)) {
            return ServiceResult.success("有红包权限");
        }
        return ServiceResult.fail("没有红包权限");*/
        return ServiceResult.success("有红包权限");
    }

}
